package com.mxpio.erp.common.order.service.impl;

import java.math.BigDecimal;
import java.util.*;

import com.mxpio.erp.common.enums.InspectionEnums;
import com.mxpio.erp.common.quality.entity.InspectionBill;
import com.mxpio.erp.common.quality.entity.UnqualifiedDisposal;
import com.mxpio.erp.common.quality.entity.UnqualifiedDisposalLine;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums.CloseStatus;
import com.mxpio.erp.common.inventory.entity.InvFlow;
import com.mxpio.erp.common.inventory.entity.WarehouseOrder;
import com.mxpio.erp.common.inventory.entity.WarehouseOrderLine;
import com.mxpio.erp.common.jpa.model.Notice;
import com.mxpio.erp.common.jpa.model.NoticeLine;
import com.mxpio.erp.common.jpa.model.OrderLine;
import com.mxpio.erp.common.jpa.model.OrderLineKey;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.system.service.impl.BaseServiceImpl;

@Service
public class OrderLineServiceImpl extends BaseServiceImpl<OrderLine> implements OrderLineService {

	@Override
	@Transactional(readOnly = false)
	public Result<? extends OrderLine> updateCloseStatus(Class<? extends OrderLine> clazz, String ids, CloseStatus closeStatus) {
		String[] id = ids.split(",");
        for(String key : id){
            String[] pk = key.split(":");
            OrderLineKey lineKey = new OrderLineKey();
            lineKey.setBizNo(pk[0]);
            lineKey.setLineNo(pk[1]);
            OrderLine bizOrderLine = JpaUtil.getOne(clazz, lineKey);
            bizOrderLine.setCloseStatus(closeStatus.getStatusCode());
            this.update(bizOrderLine);
        }
        return Result.OK();
	}

	@Override
	@Transactional(readOnly = true)
	public void handleBizOrderLineQuantity(List<? extends OrderLine> orderLines, List<NoticeClassVo> noticeClassVos, String accessType) {
		Map<String, BigDecimal> quantity = new HashMap<>();
		//Map<String, List<OrderLine>> map = orderLines.stream().collect(Collectors.groupingBy(OrderLine::getBizNo));
		Set<String> bizNos = new HashSet<>();
		orderLines.forEach(item ->bizNos.add(item.getBizNo()));
		//1.通过InvFlow计算实际执行数量
		List<InvFlow> flows = JpaUtil.linq(InvFlow.class).in("originBizNo", bizNos).list();
		for(InvFlow flow : flows){
			
			//  若流水的AccessType为参数accessType 则为执行，否则为退货
			if(accessType.equals(flow.getAccessType())){
				BigDecimal actualQuantity = quantity.get("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo());
				if(actualQuantity == null){
					actualQuantity = BigDecimal.ZERO;
				}
				actualQuantity = actualQuantity.add(flow.getQuantity());
				quantity.put("actual:"+flow.getOriginBizNo()+flow.getOriginBizLineNo(), actualQuantity);
			}else{
				BigDecimal actualRejectQuantity = quantity.get("actualReject:"+flow.getOriginBizNo()+flow.getOriginBizLineNo());
				if(actualRejectQuantity == null){
					actualRejectQuantity = BigDecimal.ZERO;
				}
				actualRejectQuantity = actualRejectQuantity.add(flow.getQuantity());
				quantity.put("actualReject:"+flow.getOriginBizNo()+flow.getOriginBizLineNo(), actualRejectQuantity);
			}
			
		}
		
		//2根据通知单和仓单计算计划数量
		//2.1计算通知单数量
		List<Notice> notices = new ArrayList<>();
		for(NoticeClassVo noticeClassVo : noticeClassVos){
			List<Notice> list = JpaUtil.linq(noticeClassVo.getNoticeClazz()).collect("noticeNo", noticeClassVo.getNoticeLineClazz(), "noticeNo")
					.equal("noticeStatus", NoticeStatusEnums.NoticeStatus.CREATE.getStatusCode()).in("bizOrderNo", bizNos)
					.list();
			notices.addAll(list);
		}
		for(Notice notice : notices){
			// 若通知单的AccessType为参数accessType 则为执行，否则为退货
			if(accessType.equals(notice.getAccessType())){
				for(NoticeLine line : notice.getNoticeLines()){
					BigDecimal planQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo());
					if(planQuantity == null){
						planQuantity = BigDecimal.ZERO;
					}
					planQuantity = planQuantity.add(line.getQuantity());
					quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planQuantity);
				}
			}else{
				for(NoticeLine line : notice.getNoticeLines()){
					BigDecimal planRejectQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo());
					if(planRejectQuantity == null){
						planRejectQuantity = BigDecimal.ZERO;
					}
					planRejectQuantity = planRejectQuantity.add(line.getQuantity());
					quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planRejectQuantity);
				}
			}
		}
		// 2.2 计算未完成仓单数量
		List<WarehouseOrder> wos = JpaUtil.linq(WarehouseOrder.class)
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode())
				.notEqual("orderStatus", OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())
				.in("originBizNo", bizNos).list();
		Map<String, WarehouseOrder> wosMap = JpaUtil.index(wos);
		
		List<InvFlow> invFlows = JpaUtil.linq(InvFlow.class).in("woBizNo", wosMap.keySet()).list();
		Map<String, BigDecimal> flowMap = new HashMap<>();
		invFlows.forEach(flow -> {
			BigDecimal sumQuantity = flowMap.get(flow.getWoBizNo()+flow.getWoBizLineNo());
			if(sumQuantity == null){
				sumQuantity = BigDecimal.ZERO;
			}
			if(accessType.equals(flow.getAccessType())){
				sumQuantity = sumQuantity.add(flow.getQuantity());
			}else{
				sumQuantity = sumQuantity.subtract(flow.getQuantity());
			}
			flowMap.put(flow.getWoBizNo()+flow.getWoBizLineNo(), sumQuantity);
		});
		
		List<WarehouseOrderLine> woLines = JpaUtil.linq(WarehouseOrderLine.class)
				.in("bizNo", wosMap.keySet())
				.equal("closeStatus", OrderStatusEnums.CloseStatus.OPEN.getStatusCode()).list();
		for(WarehouseOrderLine woLine : woLines){
			if(accessType.equals(wosMap.get(woLine.getBizNo()).getAccessType())){
				BigDecimal planQuantity = quantity.get("plan:"+woLine.getOriginBizNo()+woLine.getOriginBizLineNo());
				BigDecimal sumQuantity = flowMap.get(woLine.getBizNo()+woLine.getLineNo());
				if(planQuantity == null){
					planQuantity = BigDecimal.ZERO;
				}
				if(sumQuantity == null){
					sumQuantity = BigDecimal.ZERO;
				}
				planQuantity = planQuantity.add(woLine.getQuantity().subtract(sumQuantity));
				quantity.put("plan:"+woLine.getOriginBizNo()+woLine.getOriginBizLineNo(), planQuantity);
			}else{
				BigDecimal planRejectQuantity = quantity.get("planReject:"+woLine.getOriginBizNo()+woLine.getOriginBizLineNo());
				BigDecimal sumQuantity = flowMap.get(woLine.getBizNo()+woLine.getLineNo());
				if(planRejectQuantity == null){
					planRejectQuantity = BigDecimal.ZERO;
				}
				if(sumQuantity == null){
					sumQuantity = BigDecimal.ZERO;
				}
				planRejectQuantity = planRejectQuantity.add(woLine.getQuantity().add(sumQuantity));
				quantity.put("planReject:"+woLine.getOriginBizNo()+woLine.getOriginBizLineNo(), planRejectQuantity);
			}
		}

		//4.考虑生成的未检完成的质检单，归为计划部分
		List<InspectionBill> inspectionBills = JpaUtil.linq(InspectionBill.class)
				.notEqual("checkStatus", "3")//1计划，2检验中，3检验完成
				.equal("busiType", InspectionEnums.ISBusiType.Stock.getCode())
				.in("originBizNo", bizNos).list();
		for(InspectionBill line : inspectionBills){
			if(StringUtils.equals(InspectionEnums.OriginBizType.SALERE.getCode(),line.getOriginBizType())){//销售退货时，值统计在计划退字段中
				BigDecimal planRejQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo());
				if(planRejQuantity == null){
					planRejQuantity = BigDecimal.ZERO;
				}
				planRejQuantity = planRejQuantity.add(line.getQuantity());
				quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planRejQuantity);
			}else{
				BigDecimal planQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo());
				if(planQuantity == null){
					planQuantity = BigDecimal.ZERO;
				}
				planQuantity = planQuantity.add(line.getQuantity());
				quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planQuantity);
			}
		}
		List<String> bpmnStatusList = Arrays.asList(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode(), OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
		//5.考虑未审核通过的不良品处理单，归为计划部分
		List<UnqualifiedDisposalLine> unqualifiedDisposalLines = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class, "inspectionBillNo")
				.exists(UnqualifiedDisposal.class)
				.equalProperty("bizNo", "bizNo")
				.in("bpmnStatus", bpmnStatusList)
				.end()
				.exists(InspectionBill.class)
				.equalProperty("bizNo", "inspectionBillNo")
				.in("originBizNo", bizNos)
				.end()
				.list();
		if (!unqualifiedDisposalLines.isEmpty()){
			for(UnqualifiedDisposalLine disposalLine : unqualifiedDisposalLines){
				InspectionBill line = disposalLine.getInspectionBill();
				if (StringUtils.equals(InspectionEnums.ISBusiType.Stock.getCode(),line.getBusiType())){
					if(StringUtils.equals(InspectionEnums.OriginBizType.SALERE.getCode(),line.getOriginBizType())){//销售退货时，值统计在计划退字段中
						BigDecimal planRejQuantity = quantity.get("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo());
						if(planRejQuantity == null){
							planRejQuantity = BigDecimal.ZERO;
						}
						planRejQuantity = planRejQuantity.add(disposalLine.getApplyQuantity());
						quantity.put("planReject:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planRejQuantity);
					}else{
						BigDecimal planQuantity = quantity.get("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo());
						if(planQuantity == null){
							planQuantity = BigDecimal.ZERO;
						}
						planQuantity = planQuantity.add(disposalLine.getApplyQuantity());
						quantity.put("plan:"+line.getOriginBizNo()+line.getOriginBizLineNo(), planQuantity);
					}
				}
			}
		}



		orderLines.forEach(orderLine -> {
			orderLine.setActualQuantity(quantity.get("actual:"+orderLine.getBizNo()+orderLine.getLineNo())==null?BigDecimal.ZERO:quantity.get("actual:"+orderLine.getBizNo()+orderLine.getLineNo()));
			orderLine.setActualRejectQuantity(quantity.get("actualReject:"+orderLine.getBizNo()+orderLine.getLineNo())==null?BigDecimal.ZERO:quantity.get("actualReject:"+orderLine.getBizNo()+orderLine.getLineNo()));
			orderLine.setPlanQuantity(quantity.get("plan:"+orderLine.getBizNo()+orderLine.getLineNo())==null?BigDecimal.ZERO:quantity.get("plan:"+orderLine.getBizNo()+orderLine.getLineNo()));
			orderLine.setPlanRejectQuantity(quantity.get("planReject:"+orderLine.getBizNo()+orderLine.getLineNo())==null?BigDecimal.ZERO:quantity.get("planReject:"+orderLine.getBizNo()+orderLine.getLineNo()));
		});
	}

}
